package idgen2

import (
	"fmt"
	"math/big"
	"math/rand"
	"sync"
	"time"
)

const (
	// 各字段位数
	VersionBits     = 4
	BusinessBits    = 6
	TimestampBits   = 45
	DatacenterBits  = 8
	MachineBits     = 10
	AccountBits     = 32
	SequenceBits    = 16
	RandomBits      = 5
	EnvironmentBits = 1

	// 各字段最大值
	MaxVersion     = -1 ^ (-1 << VersionBits)
	MaxBusiness    = -1 ^ (-1 << BusinessBits)
	MaxDatacenter  = -1 ^ (-1 << DatacenterBits)
	MaxMachine     = -1 ^ (-1 << MachineBits)
	MaxAccount     = -1 ^ (-1 << AccountBits)
	MaxSequence    = -1 ^ (-1 << SequenceBits)
	MaxRandom      = -1 ^ (-1 << RandomBits)
	MaxEnvironment = -1 ^ (-1 << EnvironmentBits)

	// 位移
	VersionShift     = 127 - VersionBits
	BusinessShift    = VersionShift - BusinessBits
	TimestampShift   = BusinessShift - TimestampBits
	DatacenterShift  = TimestampShift - DatacenterBits
	MachineShift     = DatacenterShift - MachineBits
	AccountShift     = MachineShift - AccountBits
	SequenceShift    = AccountShift - SequenceBits
	RandomShift      = SequenceShift - RandomBits
	EnvironmentShift = RandomShift - EnvironmentBits

	// 开始时间戳 (2024-01-01 00:00:00 UTC)
	epoch int64 = 1704067200000
)

// Environment 环境类型
type Environment int64

const (
	// Test 测试环境
	Test Environment = 0
	// Production 生产环境
	Production Environment = 1
)

// Config 生成器配置
type Config struct {
	Version     int64       // 版本号
	Business    int64       // 业务类型
	Datacenter  int64       // 数据中心ID
	Machine     int64       // 机器ID
	Account     int64       // 账户ID
	Environment Environment // 环境类型
}

// DefaultConfig 默认配置
var DefaultConfig = Config{
	Version:     1,
	Business:    1,
	Datacenter:  1,
	Machine:     1,
	Account:     1,
	Environment: Production,
}

// Generator ID生成器
type Generator struct {
	mu            sync.Mutex
	lastTimestamp int64
	sequence      int64
	random        *rand.Rand

	// 配置信息
	version     int64
	business    int64
	datacenter  int64
	machine     int64
	account     int64
	environment int64
}

// NewGenerator 创建新的生成器
func NewGenerator(config Config) (*Generator, error) {
	// 验证配置
	if config.Version < 0 || config.Version > MaxVersion {
		return nil, fmt.Errorf("version must be between 0 and %d", MaxVersion)
	}
	if config.Business < 0 || config.Business > MaxBusiness {
		return nil, fmt.Errorf("business must be between 0 and %d", MaxBusiness)
	}
	if config.Datacenter < 0 || config.Datacenter > MaxDatacenter {
		return nil, fmt.Errorf("datacenter must be between 0 and %d", MaxDatacenter)
	}
	if config.Machine < 0 || config.Machine > MaxMachine {
		return nil, fmt.Errorf("machine must be between 0 and %d", MaxMachine)
	}
	if config.Account < 0 || config.Account > MaxAccount {
		return nil, fmt.Errorf("account must be between 0 and %d", MaxAccount)
	}
	if config.Environment < 0 || config.Environment > MaxEnvironment {
		return nil, fmt.Errorf("environment must be between 0 and %d", MaxEnvironment)
	}

	return &Generator{
		version:     config.Version,
		business:    config.Business,
		datacenter:  config.Datacenter,
		machine:     config.Machine,
		account:     config.Account,
		environment: int64(config.Environment),
		random:      rand.New(rand.NewSource(time.Now().UnixNano())),
	}, nil
}

// NextID 生成下一个ID
func (g *Generator) NextID() (string, error) {
	g.mu.Lock()
	defer g.mu.Unlock()

	now := time.Now().UnixMilli()
	if now < g.lastTimestamp {
		return "", fmt.Errorf("clock moved backwards. refusing to generate id for %d milliseconds", g.lastTimestamp-now)
	}

	if now == g.lastTimestamp {
		g.sequence = (g.sequence + 1) & MaxSequence
		if g.sequence == 0 {
			time.Sleep(time.Millisecond)
			now = time.Now().UnixMilli()
		}
	} else {
		g.sequence = 0
	}

	g.lastTimestamp = now

	// 生成随机数
	random := g.random.Int63n(MaxRandom + 1)

	// 使用 big.Int 组合ID
	id := new(big.Int)
	id.Lsh(big.NewInt(g.version), VersionShift)
	id.Or(id, new(big.Int).Lsh(big.NewInt(g.business), BusinessShift))
	id.Or(id, new(big.Int).Lsh(big.NewInt(now-epoch), TimestampShift))
	id.Or(id, new(big.Int).Lsh(big.NewInt(g.datacenter), DatacenterShift))
	id.Or(id, new(big.Int).Lsh(big.NewInt(g.machine), MachineShift))
	id.Or(id, new(big.Int).Lsh(big.NewInt(g.account), AccountShift))
	id.Or(id, new(big.Int).Lsh(big.NewInt(g.sequence), SequenceShift))
	id.Or(id, new(big.Int).Lsh(big.NewInt(random), RandomShift))
	id.Or(id, new(big.Int).Lsh(big.NewInt(g.environment), EnvironmentShift))

	return ToBase62(id), nil
}

// base62 字符集
const base62Chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"

// ToBase62 将 big.Int 转换为base62字符串
func ToBase62(num *big.Int) string {
	if num.Sign() == 0 {
		return "0"
	}

	base := big.NewInt(62)
	mod := new(big.Int)
	div := new(big.Int)
	result := make([]byte, 0, 22)

	for num.Sign() > 0 {
		div.DivMod(num, base, mod)
		result = append([]byte{base62Chars[mod.Int64()]}, result...)
		num.Set(div)
	}
	return string(result)
}

// FromBase62 将base62字符串转换为 big.Int
func FromBase62(str string) (*big.Int, error) {
	result := new(big.Int)
	base := big.NewInt(62)
	for _, c := range str {
		result.Mul(result, base)
		if c >= '0' && c <= '9' {
			result.Add(result, big.NewInt(int64(c-'0')))
		} else if c >= 'A' && c <= 'Z' {
			result.Add(result, big.NewInt(int64(c-'A'+10)))
		} else if c >= 'a' && c <= 'z' {
			result.Add(result, big.NewInt(int64(c-'a'+36)))
		} else {
			return nil, fmt.Errorf("invalid character in base62 string: %c", c)
		}
	}
	return result, nil
}

// 全局单例
var (
	defaultGenerator *Generator
	once             sync.Once
)

// getDefaultGenerator 获取默认生成器实例
func getDefaultGenerator() (*Generator, error) {
	var initErr error
	once.Do(func() {
		defaultGenerator, initErr = NewGenerator(DefaultConfig)
	})
	if initErr != nil {
		return nil, fmt.Errorf("failed to initialize default generator: %w", initErr)
	}
	return defaultGenerator, nil
}

// Generate 生成ID
func Generate() (string, error) {
	generator, err := getDefaultGenerator()
	if err != nil {
		return "", err
	}
	return generator.NextID()
}
